/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package gamaze;

import java.awt.Point;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * This object reads in a text file that represents a maze.
 * @author pborrego
 */
public class Maze {
    public final static int N = 1;
    public final static int E = 2;
    public final static int S = 4;
    public final static int W = 8;

    public Maze(String mazepath)
    {
        this.width = 0;
        this.height = 0;
        this.start = -1;
        this.end = -1;
        this.cursor = -1;
        
        try {
            read(mazepath);
        }
        catch(Exception e)
        {
            System.err.println(e.toString());
        }
    }

    public Maze(int w, int h, int s, int e, int[] m)
    {
        this.width = w;
        this.height = h;
        this.start = s;
        this.end = e;
        this.map = new int[this.width * this.height];
        System.arraycopy(m, 0, this.map, 0, this.width * this.height);

        this.cursor = this.start;
    }

    public boolean finished()
    {
        return this.cursor == this.end;
    }

    public final void read(String m) throws Exception
    {
        try
        {
            FileReader fr = new FileReader(m); // read a file
            BufferedReader br = new BufferedReader(fr);
            String tmp;

            tmp = br.readLine(); // read first line of file.

            String data[] = tmp.split(",");
            this.width = Integer.parseInt(data[0]);
            this.height = Integer.parseInt(data[1]);
            this.start = Integer.parseInt(data[2]);
            this.end = Integer.parseInt(data[3]);
            this.map = new int[width * height];

            if(data.length - 4 != width * height)
                throw new Exception("Incorrect maze data size.");

            for(int i=0; i<width * height; i++)
            {
                this.map[i] = Integer.parseInt(data[i+4]);
            }

            this.cursor = this.start;
            br.close();
        }
        catch (FileNotFoundException e)
        {
            System.err.println(e.toString());
        }
        catch (IOException e)
        {
            System.err.println(e.toString());
        }
    }

    public void reset()
    {
        this.cursor = this.start;
    }

    public boolean validPath(String p)
    {
        this.reset();
        while(p.compareTo("") > 0)
        {
            if(!this.move(Integer.parseInt(p.substring(0, 1))))
            {
                return false;
            }

            p = p.substring(1);
        }
        
        return this.finished();
    }

    public boolean move(int direction)
    {
        // check if direction is possible.
        // if so then move else return false

        if((direction & map[this.cursor]) != direction)
        {
            return false;
        }

        Point pos = cursorPoint();

        switch(direction)
        {
            case Maze.N:
                pos.y--;
                break;
            case Maze.E:
                pos.x++;
                break;
            case Maze.S:
                pos.y++;
                break;
            case Maze.W:
                pos.x--;
                break;
        }

        this.cursor = cursorPoint(pos);
        return true;
    }

    @Override
    public String toString()
    {
        String maze;

        maze = this.width + "," + this.height + "," + this.start + "," + this.end;
        for(int i=0; i< this.map.length; i++)
            maze += "," + this.map[i];

        return maze;
    }

    protected Point cursorPoint()
    {
        Point p = new Point();

        p.x = this.cursor % this.width;
        p.y = (int) (this.cursor / this.width);

        return p;
    }

    protected int cursorPoint(Point p)
    {
        return (p.y * this.width) + p.x;
    }

    public int getStart() {
        return this.start;
    }

    public int getEnd() {
        return this.end;
    }

    public void print()
    {
        String output = "";
        String sym = "";
        String bottom = "";

        for(int i=0; i<this.width; i++)
        {
            output += " _";
        }
        output += "\n";
        
        for(int y=0; y<this.height; y++)
        {
            bottom = "";
            for(int x=0; x<this.width; x++)
            {
                if(cursorPoint(new Point(x,y)) == this.cursor) {
                    sym = (cursorPoint(new Point(x,y)) == this.start) ? "S" : "*";
                    sym = (cursorPoint(new Point(x,y)) == this.end) ? "E" : sym;
                } else {
                    sym = (cursorPoint(new Point(x,y)) == this.start) ? "s" : "x";
                    sym = (cursorPoint(new Point(x,y)) == this.end) ? "e" : sym;
                }

                switch(this.map[cursorPoint(new Point(x,y))])
                {
                    case 1:
                        output += "|" + sym;
                        bottom += "+-";
                        break;
                    case 2:
                        output += "|" + sym;
                        bottom += "+-";
                        break;
                    case 3:
                        output += "|" + sym;
                        bottom += "+-";
                        break;
                    case 4:
                        output += "|" + sym;
                        bottom += "| ";
                        break;
                    case 5:
                        output += "|" + sym;
                        bottom += "| ";
                        break;
                    case 6:
                        output += "|" + sym;
                        bottom += "| ";
                        break;
                    case 7:
                        output += "|" + sym;
                        bottom += "| ";
                        break;
                    case 8:
                        output += " " + sym;
                        bottom += " -";
                        break;
                    case 9:
                        output += " " + sym;
                        bottom += " -";
                        break;
                    case 10:
                        output += " " + sym;
                        bottom += " -";
                        break;
                    case 11:
                        output += " " + sym;
                        bottom += " -";
                        break;
                    case 12:
                        output += " " + sym;
                        bottom += "  ";
                        break;
                    case 13:
                        output += " " + sym;
                        bottom += "  ";
                        break;
                    case 14:
                        output += " " + sym;
                        bottom += "  ";
                        break;
                    case 15:
                        output += " " + sym;
                        bottom += "  ";
                        break;
                }
            }
            output += "|\n" + bottom + "|\n";
        }

        System.out.println(output);
    }

    public int[] getRestrictionMap() {
        return this.map;
    }

    public int getHeight() {
        return height;
    }

    public int getWidth() {
        return width;
    }

    
    private int cursor;
    private int width;
    private int height;
    private int start;
    private int end;
    private int[] map;
}
